home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue69 / System / DeskManager.dpr < prev    next >
Encoding:
Text File  |  2001-03-22  |  7.5 KB  |  206 lines

  1. library DeskManager;
  2.  
  3. {---------------------------------------------------------------------
  4.     Name:       DeskManager
  5.     Purpose:    Provide direct access to the desktop list-view control
  6.                 Written by Dave Jewell, 2001.
  7.                 Based on an original idea by Jeffrey Richter.
  8. -----------------------------------------------------------------------}
  9.  
  10. uses
  11.   Windows, Messages, CommCtrl, DeskManMessages;
  12.  
  13. {$R DeskManagerDlg.res}
  14.  
  15. var
  16.     Hook: HHook = 0;            // used for message chaining
  17.     AppWindow: hWnd = 0;    // handle of application window
  18.     DeskLV: hWnd = 0;           // desktop list-view handle
  19.  
  20. //------------------------------------------------------------------------------
  21. // Get a window to the ListView control which implements the desktop
  22. //------------------------------------------------------------------------------
  23.  
  24. function DeskManagerListView: HWnd; stdcall; export;
  25. var
  26.     buff: array [0..255] of Char;
  27. begin
  28.     if DeskLV = 0 then begin
  29.         DeskLV := GetWindow (GetWindow (FindWindow ('ProgMan', Nil), gw_Child), gw_Child);
  30.         if DeskLV <> 0 then begin
  31.             GetClassName (DeskLV, buff, sizeof (buff));
  32.             if buff <> 'SysListView32' then DeskLV := 0;
  33.         end;
  34.  
  35.         if DeskLV = 0 then MessageBox (0, 'Panic: Desktop ListView control not found', 'DeskManager', mb_OK);
  36.     end;
  37.  
  38.     Result := DeskLV;
  39. end;
  40.  
  41. //------------------------------------------------------------------------------
  42. // Get the thread ID of the Explorer thread which manages the desktop
  43. //------------------------------------------------------------------------------
  44.  
  45. function DeskManagerShellThread: DWord; stdcall; export;
  46. begin
  47.     Result := GetWindowThreadProcessID (DeskManagerListView, Nil);
  48. end;
  49.  
  50. function HandleGetItemText (DlgWnd: hWnd; Index: Integer): Integer;
  51. var
  52.     Count: Integer;
  53.     cds: TCopyDataStruct;
  54.     buff: array [0..255] of Char;
  55. begin
  56.     Result := 0;
  57.     Count := SendMessage (DeskManagerListView, lvm_GetItemCount, 0, 0);
  58.     if (Index >= 0) and (Index < Count) then begin
  59.         buff[0] := #0;
  60.         ListView_GetItemText (DeskManagerListView, Index, 0, buff, sizeof (buff));
  61.         cds.dwData := DM_GetItemText;
  62.         cds.cbData := lstrlen (buff) + 1;
  63.         cds.lpData := @buff;
  64.         Result := SendMessage (AppWindow, wm_CopyData, DlgWnd, Integer (@cds));
  65.     end;
  66. end;
  67.  
  68. function HandleGetItemPosition (DlgWnd: hWnd; Index: Integer): Integer;
  69. var
  70.     pt: TPoint;
  71.     Count: Integer;
  72.     cds: TCopyDataStruct;
  73. begin
  74.     Result := 0;
  75.     Count := SendMessage (DeskManagerListView, lvm_GetItemCount, 0, 0);
  76.     if (Index >= 0) and (Index < Count) then begin
  77.         ListView_GetItemPosition (DeskManagerListView, Index, pt);
  78.         cds.dwData := DM_GetItemPosition;
  79.         cds.cbData := sizeof (pt);
  80.         cds.lpData := @pt;
  81.         Result := SendMessage (AppWindow, wm_CopyData, DlgWnd, Integer (@cds));
  82.     end;
  83. end;
  84.  
  85. function HandleGetItemRect (DlgWnd: hWnd; Index: Integer): Integer;
  86. var
  87.     r: TRect;
  88.     Count: Integer;
  89.     cds: TCopyDataStruct;
  90. begin
  91.     Result := 0;
  92.     Count := SendMessage (DeskManagerListView, lvm_GetItemCount, 0, 0);
  93.     if (Index >= 0) and (Index < Count) then begin
  94.         ListView_GetItemRect (DeskManagerListView, Index, r, LVIR_Bounds);
  95.         cds.dwData := DM_GetItemRect;
  96.         cds.cbData := sizeof (r);
  97.         cds.lpData := @r;
  98.         Result := SendMessage (AppWindow, wm_CopyData, DlgWnd, Integer (@cds));
  99.     end;
  100. end;
  101.  
  102. //------------------------------------------------------------------------------
  103. // Handle a special command from the application.  The wm_CopyData mechanism
  104. // enables the app to send us an arbitrary-sized chunk of data.
  105. // Achtung!: Because wm_CopyData was sent synchronously by the app, any
  106. // response to the client *must* be posted asynchronously.
  107. //------------------------------------------------------------------------------
  108.  
  109. function HandleCommand (Msg, DataSize: Integer; Data: PChar): Integer;
  110. var
  111.     Count: Integer;
  112.     Index: PInteger absolute Data;
  113. begin
  114.     Result := 0;
  115.     Count := SendMessage (DeskManagerListView, lvm_GetItemCount, 0, 0);
  116.  
  117.     case Msg of
  118.         // -------- Set the caption of a desktop item
  119.         DM_SetItemText:
  120.         if (Index^ >= 0) and (Index^ < Count) then
  121.             Result := Integer (ListView_SetItemText (DeskManagerListView, Index^, 0, Data + sizeof (Integer)));
  122.     end;
  123. end;
  124.  
  125. //------------------------------------------------------------------------------
  126. // This is the window proc of the hidden desk manager dialog.
  127. // Runs in Explorer's process context.
  128. //------------------------------------------------------------------------------
  129.  
  130. function DeskManDlgProc (DlgWnd: hWnd; Msg, wParam, lParam: Integer): Integer; stdcall;
  131. var
  132.     cds: PCopyDataStruct absolute lParam;
  133. begin
  134.     Result := 0;
  135.  
  136.     case Msg of
  137.  
  138.         // -------- Get text of a designated item: wParam = index
  139.         DM_GetItemText:         Result := HandleGetItemText (DlgWnd, wParam);
  140.  
  141.         // -------- Get position of a designated item: wParam = index
  142.         DM_GetItemPosition:     Result := HandleGetItemPosition (DlgWnd, wParam);
  143.  
  144.         // -------- Get bounding rectangle for designated item: wParam = index
  145.         DM_GetItemRect:         Result := HandleGetItemRect (DlgWnd, wParam);
  146.  
  147.     // -------- Special command (with data block) from Application
  148.         wm_CopyData:            if HWnd(wParam) = AppWindow then Result := HandleCommand (cds^.dwData, cds^.cbData, cds^.lpData);
  149.  
  150.         // -------- Destroy the dialog window
  151.         wm_Close:               DestroyWindow (DlgWnd);
  152.     end;
  153. end;
  154.  
  155. //------------------------------------------------------------------------------
  156. // Implement the message hook.  Runs in Explorer's process context
  157. //------------------------------------------------------------------------------
  158.     
  159. function GetMsgProc (nCode: Integer; wParam: wParam; lParam: lParam): lParam; stdcall;
  160. begin
  161.     if Hook = 0 then begin
  162.         Hook := (PMsg (lParam))^.lParam;
  163.         // Create the server window to service client requests
  164.         CreateDialog (hInstance, PChar (101), 0, @DeskManDlgProc);
  165.     // Get application window handle
  166.     AppWindow := (PMsg (lParam))^.wParam;
  167.         // Tell the original application that server is ready
  168.         PostMessage (AppWindow, DM_DLLReady, 0, 0);
  169.     end;
  170.  
  171.     Result := CallNextHookEx (Hook, nCode, wParam, lParam);
  172. end;
  173.  
  174. //------------------------------------------------------------------------------
  175. // Initialise and inject the DLL.  Runs in the client application context
  176. //------------------------------------------------------------------------------
  177.  
  178. function DeskManagerLoad (AppWindow: hWnd): Bool; stdcall; export;
  179. begin
  180.     Result := False;
  181.     // Various safety checks...
  182.     if (Hook = 0) and (FindWindow (Nil, 'Delphi Desktop 2001') = 0) then begin
  183.         // Hook the desktop thread
  184.         Hook := SetWindowsHookEx (wh_GetMessage, @GetMsgProc, hInstance, DeskManagerShellThread);
  185.         Result := Hook <> 0;
  186.         // If success, post a message to force DLL injection
  187.         if Result then Result := PostThreadMessage (DeskManagerShellThread, wm_Null, AppWindow, Hook);
  188.     end;
  189. end;
  190.  
  191. function DeskManagerUnload: Bool; stdcall; export;
  192. begin
  193.     if Hook <> 0 then Result := UnhookWindowsHookEx (Hook) else Result := False;
  194.     Hook := 0;
  195. end;
  196.  
  197. exports
  198.     DeskManagerLoad,
  199.     DeskManagerUnload,
  200.     DeskManagerListView,
  201.     DeskManagerShellThread;
  202.  
  203. begin
  204. end.
  205.  
  206.